package com.gzist.elderlyserviceplatform.service;

import com.gzist.elderlyserviceplatform.interceptors.exceptions.FileOperationException;
import com.gzist.elderlyserviceplatform.interceptors.exceptions.PdfGenerationException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * PDF转换服务（生产环境优化版）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PdfConverterService {
    private final MinioFileService minioFileService;

    private static final String SERVER_FONT_PATH = "/usr/share/fonts/simsun.ttc";
    private static final String CLASSPATH_FONT_PATH = "fonts/simsun.ttc";
    private static final BaseFont SIMSUN_FONT = initServerBaseFont();

    /**
     * 多环境字体加载策略（[[3]](#__3) [[6]](#__6)）
     */
    private static BaseFont initServerBaseFont() {
        try {
            // 生产环境优先加载
            if (Files.isReadable(Paths.get(SERVER_FONT_PATH))) {
                log.info("加载服务器字体: {}", SERVER_FONT_PATH);
                return BaseFont.createFont(
                        SERVER_FONT_PATH + ",0",
                        BaseFont.IDENTITY_H,
                        BaseFont.EMBEDDED
                );
            }
            // 开发环境尝试Classpath加载
            log.warn("尝试从Classpath加载字体: {}", CLASSPATH_FONT_PATH);
            try (InputStream fontStream =
                         PdfConverterService.class.getClassLoader()
                                 .getResourceAsStream(CLASSPATH_FONT_PATH)) {
                if (fontStream == null) {
                    log.error("Classpath字体文件不存在: {}", CLASSPATH_FONT_PATH);
                    throw new IOException("Classpath字体文件不存在");
                }
                byte[] fontData = IOUtils.toByteArray(fontStream);
                log.info("成功从Classpath加载字体: {}", CLASSPATH_FONT_PATH);
                return BaseFont.createFont(
                        "simsun.ttc,0",   // 字体标识 + 索引（关键修改）
                        BaseFont.IDENTITY_H,
                        BaseFont.EMBEDDED,
                        true,             // 强制读取字节流
                        fontData,         // 字节数据
                        null              // 索引已包含在字体标识中，此处可为 null
                );
            }
        } catch (Exception e) {
            log.error("字体初始化失败，使用系统默认字体", e);
            // 强制回退到默认字体，避免初始化失败
            try {
                return BaseFont.createFont(
                        BaseFont.HELVETICA,
                        BaseFont.WINANSI,
                        BaseFont.EMBEDDED
                );
            } catch (Exception ex) {
                throw new RuntimeException("无法加载默认字体", ex);
            }
        }
    }

    /**
     * PDF生成与上传主流程
     */
    public String convertToPdfAndUpload(String markdownContent) {
        try (ByteArrayOutputStream pdfStream = new ByteArrayOutputStream()) {
            // 生成PDF字节流
            byte[] pdfBytes = generatePdf(markdownContent);

            // 封装MultipartFile
            MultipartFile pdfFile = new MockMultipartFile(
                    "elderly_report.pdf",
                    "elderly_report.pdf",
                    "application/pdf",
                    pdfBytes
            );

            // 上传至MinIO
            return minioFileService.uploadFile(pdfFile);
        } catch (DocumentException e) {
            log.error("PDF文档结构异常: {}", e.getMessage());
            throw new PdfGenerationException("文档格式校验失败");
        } catch (IOException e) {
            log.error("文件IO异常: {}", e.getMessage());
            throw new FileOperationException("文件处理流程中断");
        } catch (Exception e) {
            log.error("未知系统异常: {}", e.getMessage());
            throw new RuntimeException("系统服务异常");
        }
    }

    /**
     * PDF生成核心方法（[[1]](#__1) [[5]](#__5)）
     */
    private byte[] generatePdf(String markdown) throws DocumentException, IOException {
        // Markdown转HTML
        String htmlContent = convertMarkdownToHtml(markdown);

        // 构建带样式的HTML文档
        String fullHtml = buildHtmlTemplate(htmlContent);

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
             InputStream htmlInput = new ByteArrayInputStream(fullHtml.getBytes(StandardCharsets.UTF_8))) {

            Document document = new Document();
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);

            // 文档元数据设置
            document.addAuthor("ElderlyServicePlatform");
            document.addCreationDate();
            document.addTitle("老年人健康报告");

            document.open();

            // XML解析配置（[[6]](#__6)）
            XMLWorkerHelper.getInstance().parseXHtml(
                    writer,
                    document,
                    htmlInput,
                    StandardCharsets.UTF_8,
                    new ServerFontProvider()
            );

            document.close();
            return outputStream.toByteArray();
        }
    }

    /**
     * HTML模板构建器（[[1]](#__1)）
     */
    private String buildHtmlTemplate(String bodyContent) {
        return String.join("\n",
                "<?xml version='1.0' encoding='UTF-8'?>",
                "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.1//EN' 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>",
                "<html xmlns='http://www.w3.org/1999/xhtml'>",
                "<head>",
                "  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>",
                "  <style type='text/css'>",
                "    body { font-family: SimSun, sans-serif; margin: 2cm; line-height: 1.6; }",
                "    h1 { color: #2c3e50; border-bottom: 2px solid #3498db; }",
                "    table { border-collapse: collapse; width: 100%; margin: 20px 0; }",
                "    th { background: #3498db; color: white; padding: 12px; }",
                "    td { padding: 10px; border: 1px solid #ddd; }",
                "    @font-face { font-family: 'SimSun'; src: url('" + SERVER_FONT_PATH + "'); }",
                "  </style>",
                "</head>",
                "<body>" + bodyContent + "</body>",
                "</html>"
        );
    }

    /**
     * 增强字体提供器（[[3]](#__3) [[6]](#__6)）
     */
    private static class ServerFontProvider extends XMLWorkerFontProvider {
        @Override
        public Font getFont(String fontname, String encoding,
                            boolean embedded, float size, int style) {
            try {
                // 主字体方案
                return new Font(SIMSUN_FONT, size, style);
            } catch (Exception ex) {
                log.warn("主字体异常，启用备用方案");
                try {
                    // 系统备用字体
                    return super.getFont(
                            "SimSun",
                            "UniGB-UCS2-H",
                            true,   // 强制嵌入
                            size,
                            style
                    );
                } catch (Exception e) {
                    log.error("备用字体加载失败，启用系统默认字体");
                    // 最终回退方案
                    return super.getFont(
                            BaseFont.HELVETICA,
                            BaseFont.WINANSI,
                            BaseFont.EMBEDDED
                    );
                }
            }
        }
    }

    /**
     * Markdown转HTML（[[1]](#__1)）
     */
    private String convertMarkdownToHtml(String markdown) {
        Parser parser = Parser.builder().build();
        Node document = parser.parse(markdown);
        return HtmlRenderer.builder().build().render(document);
    }
}
